package client;

import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

import java.awt.Color;

import javax.swing.border.TitledBorder;
import javax.swing.border.LineBorder;
import javax.swing.text.DefaultCaret;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.AbstractAction;

import java.awt.event.ActionEvent;

import javax.swing.Action;

import org.eclipse.wb.swing.FocusTraversalOnArray;

import java.awt.Component;
import java.awt.Font;

import javax.swing.JCheckBox;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;

public class ButtonPanel extends JPanel
{
	private static final long serialVersionUID = -6498078148606969635L;

	JSpinner spinnerBet = new JSpinner();
	
	JLabel lblIp = new JLabel("IP");
	JTextField ipField = new JTextField("localhost");
	JLabel lblPort = new JLabel("Port");
	JTextField portField = new JTextField("9090");
	JCheckBox chckbxBotMode = new JCheckBox("Bot mode");
	
	JButton btnCheck = new JButton("Check");
	JButton btnBet = new JButton("Bet");
	JButton btnRaise = new JButton("Raise");
	JButton btnCall = new JButton("Call");
	JButton btnFold = new JButton("Fold");
	JButton btnAllIn = new JButton("All-in");
	JButton btnConnect = new JButton("Connect");
	JCheckBox chckbxShowConsole = new JCheckBox("Show console");
	JButton btnExchangeCards = new JButton("Exchange cards");
	JScrollPane serverMessageScrollPane = new JScrollPane();
	JTextArea serverMessage = new JTextArea();
	JButton btnDontExchange = new JButton("Don't exchange");
	
	private final Action connectAction = new ConnectAction();
	private final Action checkAction = new CheckAction();
	private final Action callAction = new CallAction();
	private final Action betAction = new BetAction();
	private final Action raiseAction = new RaiseAction();
	private final Action allinAction = new AllinAction();
	private final Action foldAction = new FoldAction();
	
	ClientBadugi client;
	private final JPanel consolePanel = new JPanel();
	private final Action showConsoleAction = new ShowConsoleAction();
	private final Action exchangeCardsAction = new ExchangeCardsAction();
	private final Action dontExchangeAction = new DontExchangeAction();
	private final Action botModeAction = new BotModeAction();
	
	
	/**
	 * Create the panel.
	 */
	public ButtonPanel(ClientBadugi client)
	{
		this();
		this.client = client;
	}
	
	public ButtonPanel()
	{

		setBorder(new BevelBorder(BevelBorder.RAISED, null, null, null, null));
		setLayout(null);
		
		JPanel serverPanel = new JPanel();
		serverPanel.setBorder(new TitledBorder(new LineBorder(new Color(128, 128, 128)), "Server", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0)));
		serverPanel.setBounds(10, 8, 203, 99);
		add(serverPanel);
		serverPanel.setLayout(null);
		
		
		ipField.setBounds(35, 19, 158, 20);
		serverPanel.add(ipField);
		
		lblIp.setBounds(10, 22, 18, 14);
		serverPanel.add(lblIp);		
		
		btnConnect.setAction(connectAction);
		btnConnect.setBounds(109, 45, 84, 23);
		serverPanel.add(btnConnect);
		
		lblPort.setBounds(10, 50, 28, 14);
		serverPanel.add(lblPort);
		
		portField.setBounds(35, 47, 64, 20);
		serverPanel.add(portField);
		portField.setColumns(10);
		chckbxBotMode.setAction(botModeAction); // wlaczanie bota
		
		chckbxBotMode.setBounds(6, 71, 97, 23);
		
		serverPanel.add(chckbxBotMode);
		consolePanel.setBorder(new TitledBorder(new LineBorder(new Color(128, 128, 128)), "Console", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0)));
		consolePanel.setBounds(10, 394, 203, 155);
		
		add(consolePanel);
		consolePanel.setLayout(null);
		serverMessageScrollPane.setBounds(10, 17, 183, 127);
		consolePanel.add(serverMessageScrollPane);
		serverMessageScrollPane.setViewportView(serverMessage);
		serverMessage.setTabSize(3);
		serverMessage.setFont(new Font("Monospaced", Font.PLAIN, 10));
		serverMessage.setEditable(false);
		/* Auto scroll */
		DefaultCaret caret = (DefaultCaret)serverMessage.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
		
		JPanel gameControlPanel = new JPanel();
		gameControlPanel.setBorder(new TitledBorder(new LineBorder(new Color(128, 128, 128)), "Game control", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0)));
		gameControlPanel.setBounds(10, 110, 203, 281);
		add(gameControlPanel);
		gameControlPanel.setLayout(null);
		
		btnCheck.setBounds(47, 21, 108, 23);
		gameControlPanel.add(btnCheck);
		btnCheck.setAction(checkAction);
		
		btnCall.setBounds(47, 46, 108, 23);
		gameControlPanel.add(btnCall);
		btnCall.setAction(callAction);
		
		btnBet.setBounds(47, 71, 108, 23);
		gameControlPanel.add(btnBet);
		btnBet.setAction(betAction);
		
		spinnerBet.setBounds(47, 96, 108, 23);
		gameControlPanel.add(spinnerBet);
		
		btnRaise.setBounds(47, 121, 108, 23);
		gameControlPanel.add(btnRaise);
		btnRaise.setAction(raiseAction);
		
		btnAllIn.setBounds(47, 146, 108, 23);
		gameControlPanel.add(btnAllIn);
		btnAllIn.setAction(allinAction);
		
		btnFold.setBounds(47, 171, 108, 23);
		gameControlPanel.add(btnFold);
		btnFold.setAction(foldAction);
		
		chckbxShowConsole.setSelected(true);
		chckbxShowConsole.setAction(showConsoleAction);
		chckbxShowConsole.setBounds(6, 251, 108, 23);
		gameControlPanel.add(chckbxShowConsole);
		
		btnExchangeCards.setAction(exchangeCardsAction);
		btnExchangeCards.setBounds(47, 196, 108, 23);
		gameControlPanel.add(btnExchangeCards);
		
		btnDontExchange.setAction(dontExchangeAction);
		btnDontExchange.setBounds(47, 221, 108, 23);
		gameControlPanel.add(btnDontExchange);
		
		setFocusTraversalPolicy(new FocusTraversalOnArray(new Component[]{ipField, portField, btnConnect, btnCheck, btnCall, btnBet, spinnerBet, btnRaise, btnAllIn, btnFold, btnExchangeCards, btnDontExchange, chckbxShowConsole}));
		
		initPanel();
	}
	
	void initPanel()
	{
		this.setOffGameButtons();
		this.setOnConnection();
	}
	
	private void setOffGameButtons()
	{
		this.btnAllIn.setEnabled(false);
		this.btnBet.setEnabled(false);
		this.btnCall.setEnabled(false);
		this.btnCheck.setEnabled(false);
		this.btnFold.setEnabled(false);
		this.btnRaise.setEnabled(false);
		this.btnDontExchange.setEnabled(false);
		this.btnExchangeCards.setEnabled(false);
		this.spinnerBet.setEnabled(false);
	}
		
	private class ConnectAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 5882427282763295539L;
		public ConnectAction() 
		{
			putValue(NAME, "Connect");
			putValue(SHORT_DESCRIPTION, "Type IP address and port number then press Connect.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			if (client.connect(ipField.getText(), portField.getText()))
			{
				setOffConnection();
			}
		}
	}
	private class CheckAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -9136587359455533757L;
		public CheckAction() 
		{
			putValue(NAME, "Check");
			putValue(SHORT_DESCRIPTION, "If no one has betted yet in the round you can Check without chips!");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.check();
		}
	}
	private class CallAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -5573022064890071888L;
		public CallAction() 
		{
			putValue(NAME, "Call");
			putValue(SHORT_DESCRIPTION, "If someone has betted in the round you can Call with highest bet in the round.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.call();
		}
	}
	private class BetAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 4794239512948099971L;
		public BetAction() 
		{
			putValue(NAME, "Bet");
			putValue(SHORT_DESCRIPTION, "If you start the round you can bet a first bet. Don't forget to choose bet on spinner!");
		}
		public void actionPerformed(ActionEvent e) 
		{
			int bet=(int)spinnerBet.getModel().getValue();
			client.bet(bet);
			
		}
	}
	private class RaiseAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -8187138734047163395L;
		public RaiseAction() 
		{
			putValue(NAME, "Raise");
			putValue(SHORT_DESCRIPTION, "If you want to raise a bet then choose Raise with appropriate bet choosed on spinner.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			int bet=(int)spinnerBet.getModel().getValue();
			client.raise(bet);
		}
	}
	private class AllinAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 7048189653741777461L;
		public AllinAction() 
		{
			putValue(NAME, "All-in");
			putValue(SHORT_DESCRIPTION, "If you don't have enough chips to play Raise or Call you can bet all chips you have and wait till end of game.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.allin();
		}
	}
	private class FoldAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 5289628717652095370L;
		public FoldAction() 
		{
			putValue(NAME, "Fold");
			putValue(SHORT_DESCRIPTION, "If your cards are poor you can always quit the game. All chips you have betted you lose.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.fold();
		}
	}
	private class ExchangeCardsAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -697327020544547538L;
		public ExchangeCardsAction() 
		{
			putValue(NAME, "Exchange cards");
			putValue(SHORT_DESCRIPTION, "After first, second and thrid betting round you can exchange one, two, three or four cards");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.exchangeCards();
		}
	}
	private class DontExchangeAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -6533782142078955362L;
		public DontExchangeAction() 
		{
			putValue(NAME, "Don't exchange");
			putValue(SHORT_DESCRIPTION, "If you don't want exchange cards click this button. You are lucky owner of Badugi!");
		}
		public void actionPerformed(ActionEvent e) 
		{
			client.dontExchange();
		}
	}
	private class ShowConsoleAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 52556938953528371L;
		public ShowConsoleAction() 
		{
			putValue(NAME, "Show console");
			putValue(SHORT_DESCRIPTION, "Hide or show server communication console. If checkbox is checked console is  shown below.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			if(chckbxShowConsole.isSelected())
			{
				consolePanel.setVisible(true);
			}
			else
			{
				consolePanel.setVisible(false);
			}
		}
	}

	private class BotModeAction extends AbstractAction 
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = -395660014003519996L;
		public BotModeAction() {
			putValue(NAME, "Bot mode");
			putValue(SHORT_DESCRIPTION, "You can run this app as a bot. You need to this check this box and connect to the server. After connection you can not change mode application is running.");
		}
		public void actionPerformed(ActionEvent e) 
		{
			
		}
	}
	
	public void setCommunication(String s)
	{
		this.serverMessage.append(s);
	}

	public void clearCommunication()
	{
		this.serverMessage.setText("");
	}
	
	public void setOffConnection()
	{
		this.btnConnect.setEnabled(false);
		this.ipField.setEditable(false);
		this.portField.setEditable(false);
		this.chckbxBotMode.setEnabled(true);
	}

	public void setOnConnection()
	{
		this.btnConnect.setEnabled(true);
		this.ipField.setEditable(true);
		this.portField.setEditable(true);
		this.chckbxBotMode.setEnabled(true);
	}

	public boolean isBotMode()
	{
		return this.chckbxBotMode.isSelected();
	}
	
	private void setSpinner(int min, int max, int step)
	{
		spinnerBet.setModel(new SpinnerNumberModel(min, min, max, step));
	}
	
	public void setOnExchangeCards()
	{
		this.btnExchangeCards.setEnabled(true);
		this.btnDontExchange.setEnabled(true);
	}
	
	public void setOffExchangeCards()
	{
		this.btnExchangeCards.setEnabled(false);
		this.btnDontExchange.setEnabled(false);
	}
	
	public void setOnBidButtons()
	{
		this.btnAllIn.setEnabled(true);
		this.btnBet.setEnabled(true);
		this.btnCall.setEnabled(true);
		this.btnCheck.setEnabled(true);
		this.btnFold.setEnabled(true);
		this.btnRaise.setEnabled(true);
		this.spinnerBet.setEnabled(true);		
	}
	
	public void setOffBidButtons()
	{
		this.btnAllIn.setEnabled(false);
		this.btnBet.setEnabled(false);
		this.btnCall.setEnabled(false);
		this.btnCheck.setEnabled(false);
		this.btnFold.setEnabled(false);
		this.btnRaise.setEnabled(false);
		this.spinnerBet.setEnabled(false);
	}
	
	public void setButtonsToBid(int inGameChips, int highestBetInRound, int totalChips)
	{
		/* postapienie do suwaczka */
		int step = 1;

		/* CHECK ->  0 */
		/* jesli highestBetInRound == 0 to znaczy ze zaczyna sie licytacja */
		if (inGameChips == highestBetInRound || highestBetInRound == 0)
			this.btnCheck.setEnabled(true);
		
		/* CALL ->  highestBetInRound-inGameChips */
		if ((inGameChips < highestBetInRound) && (highestBetInRound - inGameChips <= totalChips) && (totalChips > 0))
			this.btnCall.setEnabled(true);
		
		/* BET -> dowolna stawka, pytanie czy rozpoczynajacy runde druga moze zrobic BET, czy musi CHECK lub RAISE */
		if ((highestBetInRound == 0) && (totalChips > 0))
		{
			this.btnBet.setEnabled(true);
			/* spinner */
			this.setSpinner(step, totalChips, step);
			this.spinnerBet.setEnabled(true);
		}
		
		/* RAISE -> dowolna stawka */
		if (inGameChips + totalChips > highestBetInRound && highestBetInRound != 0)
		{
			this.btnRaise.setEnabled(true);
			/* spinner */
			this.setSpinner(highestBetInRound - inGameChips + step, totalChips, step);
			this.spinnerBet.setEnabled(true);
		}
		
		/* ALL IN -> totalChips */
		if ((highestBetInRound - inGameChips + step > totalChips) && (totalChips > 0))
		{
			this.btnAllIn.setEnabled(true);
		}
		
		/* FOLD -> bez stawki */
		this.btnFold.setEnabled(true);
	}
}
